home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 422_02 / dosutil / grep.c < prev    next >
C/C++ Source or Header  |  1994-03-20  |  16KB  |  580 lines

  1. /*
  2.  * The  information  in  this  document  is  subject  to  change
  3.  * without  notice  and  should not be construed as a commitment
  4.  * by Digital Equipment Corporation or by DECUS.
  5.  *
  6.  * Neither Digital Equipment Corporation, DECUS, nor the authors
  7.  * assume any responsibility for the use or reliability of  this
  8.  * document or the described software.
  9.  *
  10.  *      Copyright (C) 1980, DECUS
  11.  *
  12.  * General permission to copy or modify, but not for profit,  is
  13.  * hereby  granted,  provided that the above copyright notice is
  14.  * included and reference made to  the  fact  that  reproduction
  15.  * privileges were granted by DECUS.
  16.  *
  17.  * Compile command: cc grep -fop
  18.  */
  19.  
  20. #include <stdio.h>
  21.  
  22. /*
  23.  * grep.
  24.  *
  25.  * Runs on the Decus compiler or on vms.
  26.  *
  27.  * On vms, define as:
  28.  *
  29.  *      grep :== "$disk:[account]grep"      (native)
  30.  *      grep :== "$disk:[account]grep grep" (Decus)
  31.  *
  32.  * See below for more information.
  33.  */
  34.  
  35. char    *documentation[] = {
  36. "grep searches a file for a given pattern.  Execute by",
  37. "   grep [flags] regular_expression file_list",
  38. "",
  39. "Flags are single characters preceeded by '-':",
  40. "   -c      Only a count of matching lines is printed",
  41. "   -f      Print file name for matching lines switch, see below",
  42. "   -n      Each line is preceeded by its line number",
  43. "   -v      Only print non-matching lines",
  44. "",
  45. "The file_list is a list of files (wildcards are acceptable on RSX modes).",
  46.  
  47. "",
  48. "The file name is normally printed if there is a file given.",
  49. "The -f flag reverses this action (print name no file, not if more).",
  50. "",
  51. 0 };
  52.  
  53. char    *patdoc[] = {
  54. "The regular_expression defines the pattern to search for.  Upper- and",
  55. "lower-case are always ignored.  Blank lines never match.  The expression",
  56. "should be quoted to prevent file-name translation.",
  57. "x      An ordinary character (not mentioned below) matches that character.",
  58. "'\\'    The backslash quotes any character.  \"\\$\" matches a dollar-sign.",
  59. "'^'    A circumflex at the beginning of an expression matches the",
  60. "       beginning of a line.",
  61. "'$'    A dollar-sign at the end of an expression matches the end of a line.",
  62. "'.'    A period matches any character except \"new-line\".",
  63. "':a'   A colon matches a class of characters described by the following",
  64. "':d'     character.  \":a\" matches any alphabetic, \":d\" matches digits,",
  65. "':n'     \":n\" matches alphanumerics, \": \" matches spaces, tabs, and",
  66. "': '     other control characters, such as new-line.",
  67. "'*'    An expression followed by an asterisk matches zero or more",
  68. "       occurrances of that expression: \"fo*\" matches \"f\", \"fo\"",
  69. "       \"foo\", etc.",
  70. "'+'    An expression followed by a plus sign matches one or more",
  71. "       occurrances of that expression: \"fo+\" matches \"fo\", etc.",
  72. "'-'    An expression followed by a minus sign optionally matches",
  73. "       the expression.",
  74. "'[]'   A string enclosed in square brackets matches any character in",
  75. "       that string, but no others.  If the first character in the",
  76. "       string is a circumflex, the expression matches any character",
  77. "       except \"new-line\" and the characters in the string.  For",
  78. "       example, \"[xyz]\" matches \"xx\" and \"zyx\", while \"[^xyz]\"",
  79. "       matches \"abc\" but not \"axb\".  A range of characters may be",
  80. "       specified by two characters separated by \"-\".  Note that,",
  81. "       [a-z] matches alphabetics, while [z-a] never matches.",
  82. "The concatenation of regular expressions is a regular expression.",
  83. 0};
  84.  
  85. #define LMAX    512
  86. #define PMAX    256
  87.  
  88. #define CHAR    1
  89. #define BOL     2
  90. #define EOL     3
  91. #define ANY     4
  92. #define CLASS   5
  93. #define NCLASS  6
  94. #define STAR    7
  95. #define PLUS    8
  96. #define MINUS   9
  97. #define ALPHA   10
  98. #define DIGIT   11
  99. #define NALPHA  12
  100. #define PUNCT   13
  101. #define RANGE   14
  102. #define ENDPAT  15
  103.  
  104. int cflag=0, fflag=0, nflag=0, vflag=0, nfile=0, debug=0;
  105.  
  106. char *pp, lbuf[LMAX], pbuf[PMAX];
  107.  
  108. extern char *cclass(), *pmatch();
  109.  
  110.  
  111. /*** Main program - parse arguments & grep *************/
  112. main(argc, argv)
  113. int argc;
  114. char *argv[];
  115. {
  116.    register char   *p;
  117.    register int    c, i;
  118.    int             gotpattern;
  119.  
  120.    FILE            *f;
  121.  
  122.    if (argc <= 1)
  123.       usage("No arguments");
  124.    if (argc == 2 && argv[1][0] == '?' && argv[1][1] == 0) {
  125.       help(documentation);
  126.       help(patdoc);
  127.       return;
  128.       }
  129.    nfile = argc-1;
  130.    gotpattern = 0;
  131.    for (i=1; i < argc; ++i) {
  132.       p = argv[i];
  133.       if (*p == '-') {
  134.          ++p;
  135.          while (c = *p++) {
  136.             switch(tolower(c)) {
  137.  
  138.             case '?':
  139.                help(documentation);
  140.                break;
  141.  
  142.             case 'C':
  143.             case 'c':
  144.                ++cflag;
  145.                break;
  146.  
  147.             case 'D':
  148.             case 'd':
  149.                ++debug;
  150.                break;
  151.  
  152.             case 'F':
  153.             case 'f':
  154.                ++fflag;
  155.                break;
  156.  
  157.             case 'n':
  158.             case 'N':
  159.                ++nflag;
  160.                break;
  161.  
  162.             case 'v':
  163.             case 'V':
  164.                ++vflag;
  165.                break;
  166.  
  167.             default:
  168.                usage("Unknown flag");
  169.             }
  170.          }
  171.          argv[i] = 0;
  172.          --nfile;
  173.       } else if (!gotpattern) {
  174.          compile(p);
  175.          argv[i] = 0;
  176.          ++gotpattern;
  177.          --nfile;
  178.       }
  179.    }
  180.    if (!gotpattern)
  181.       usage("No pattern");
  182.    if (nfile == 0)
  183.       grep(stdin, 0);
  184.    else {
  185.       fflag = fflag ^ (nfile > 0);
  186.       for (i=1; i < argc; ++i) {
  187.          if (p = argv[i]) {
  188.             if ((f=fopen(p, "r")) == NULL)
  189.                cant(p);
  190.             else {
  191.                grep(f, p);
  192.                fclose(f);
  193.             }
  194.          }
  195.       }
  196.    }
  197. }
  198.  
  199. /*** Display a file name *******************************/
  200. file(s)
  201. char *s;
  202. {
  203.    printf("File %s:\n", s);
  204. }
  205.  
  206. /*** Report unopenable file ****************************/
  207. cant(s)
  208. char *s;
  209. {
  210.    fprintf(stderr, "%s: cannot open\n", s);
  211. }
  212.  
  213. /*** Give good help ************************************/
  214. help(hp)
  215. char **hp;
  216. {
  217.    register char   **dp;
  218.  
  219.    for (dp = hp; *dp; ++dp)
  220.       printf("%s\n", *dp);
  221. }
  222.  
  223. /*** Display usage summary *****************************/
  224. usage(s)
  225. char    *s;
  226. {
  227.    fprintf(stderr, "?GREP-E-%s\n", s);
  228.    fprintf(stderr,
  229.       "Usage: grep [-cfnv] pattern [file ...].  grep ? for help\n");
  230.    exit(1);
  231. }
  232.  
  233. /*** Compile the pattern into global pbuf[] ************/
  234. compile(source)
  235. char       *source;   /* Pattern to compile */
  236. {
  237.    register char  *s;         /* Source string pointer     */
  238.    register char  *lp;        /* Last pattern pointer      */
  239.    register int   c;          /* Current character         */
  240.    int            o;          /* Temp                      */
  241.    char           *spp;       /* Save beginning of pattern */
  242.  
  243.    s = source;
  244.    if (debug)
  245.       printf("Pattern = \"%s\"\n", s);
  246.    pp = pbuf;
  247.    while (c = *s++) {
  248.       /*
  249.        * STAR, PLUS and MINUS are special.
  250.        */
  251.       if (c == '*' || c == '+' || c == '-') {
  252.          if (pp == pbuf ||
  253.               (o=pp[-1]) == BOL ||
  254.               o == EOL ||
  255.               o == STAR ||
  256.               o == PLUS ||
  257.               o == MINUS)
  258.             badpat("Illegal occurrance op.", source, s);
  259.          store(ENDPAT);
  260.          store(ENDPAT);
  261.          spp = pp;               /* Save pattern end     */
  262.          while (--pp > lp)       /* Move pattern down    */
  263.             *pp = pp[-1];        /* one byte             */
  264.          *pp =   (c == '*') ? STAR :
  265.             (c == '-') ? MINUS : PLUS;
  266.          pp = spp;               /* Restore pattern end  */
  267.          continue;
  268.       }
  269.       /*
  270.        * All the rest.
  271.        */
  272.       lp = pp;         /* Remember start       */
  273.       switch(c) {
  274.  
  275.       case '^':
  276.          store(BOL);
  277.          break;
  278.  
  279.       case '$':
  280.          store(EOL);
  281.          break;
  282.  
  283.       case '.':
  284.          store(ANY);
  285.          break;
  286.  
  287.       case '[':
  288.          s = cclass(source, s);
  289.          break;
  290.  
  291.